#ifndef CHECKER_H
#define CHECKER_H
#include "constants.h"
#include "process_state.h"
#include "checker.h"
#include <cstdlib>
#include <algorithm>
#include "assert.h"
#include <boost/ptr_container/ptr_vector.hpp>

class IChecker
{
public:
    IChecker():numberFalse_(0){}
    //!Return true if state is acceptable and it we have to continue.
    virtual bool check(const ProcessState& state) = 0;
    //!Return number of false returns.
    virtual size_t numberFalse() const
    {
        return numberFalse_;
    }
    virtual void incrementFalseNumber()
    {
        ++numberFalse_;
        if ((numberFalse_ & LOG_PERIOD) == 0) {
            log();
        }
    }
    virtual void log()
    {
        std::cout << name() << " break " << numberFalse()
             << " branches" << std::endl;
    }
    virtual std::string name() const = 0;
    virtual ~IChecker() {}
protected:
    size_t numberFalse_;
};

//!Helper class, which check fixed symmetric.
class SymmetricChecker
{
public:
    bool check(const ProcessState& state, size_t symmetric);
private:
    size_t vertecies_[SIZE_VMSK];
};


//!Final checker for be sure, that graph is minimal symmetric.
class FinalSymmetricChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "FinalSymmetricChecker";
    }
    ~FinalSymmetricChecker()
    {
        log();
    }

private:
    SymmetricChecker helperChecker_;
};


//!Online checker for be sure, that graph is potentially minimal symmetric
//!by reversing bits.
class OnlineSymmetricChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "OnlineSymmetricChecker";
    }
    ~OnlineSymmetricChecker()
    {
        log();
    }
private:
    SymmetricChecker helperChecker_;
};

const size_t MAX_PROCESSED = n + 2;

class CoordNChecker
{
public:
    bool check(const size_t* const a, size_t k);
private:
    size_t tmp[MAX_PROCESSED + 1][MAX_PROCESSED + 1];
};

//!Online checker for be sure, that graph is potentially minimal symmetric
//!by reordering bits.
class OnlineSymmetricCoordChecker: public IChecker
{
public:
    OnlineSymmetricCoordChecker();
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "OnlineSymmetricCoordChecker";
    }
    ~OnlineSymmetricCoordChecker()
    {
        log();
    }
private:
    std::auto_ptr<CoordNChecker> checker_;
};

//!Final checker for be sure, that graph has maximal dimension.
class FinalDimensionChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "FinalDimensionChecker";
    }
    ~FinalDimensionChecker()
    {
        log();
    }
private:
};

//!Online checker for be sure, that graph has maximal dimension.
class OnlineDimensionChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "OnlineDimensionChecker";
    }
    ~OnlineDimensionChecker()
    {
        log();
    }
private:
};

//!Final checker for be sure, that graph is not biparate.
class FinalBiparateChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "FinalBiparateChecker";
    }
    ~FinalBiparateChecker()
    {
        log();
    }
private:
};

//!Final checker for be sure, that graph could not be colored greedy algorithm.
class FinalNaiveColoringChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "FinalNaiveColoringChecker";
    }
    ~FinalNaiveColoringChecker()
    {
        log();
    }
private:
};

//!Final checker for be sure, that graph could not be colored.
class FinalCorrectColoringChecker: public IChecker
{
public:
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "FinalCorrectColoringChecker";
    }
    ~FinalCorrectColoringChecker()
    {
        log();
    }
private:
};

class OnlineMaxDegreeChecker: public IChecker
{
public:
    OnlineMaxDegreeChecker():maxDegree_(n) {}
    OnlineMaxDegreeChecker(size_t maxDegree):maxDegree_(maxDegree){}
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "OnlineMaxDegreeChecker";
    }
    ~OnlineMaxDegreeChecker()
    {
        log();
    }
private:
    size_t maxDegree_;
};

class OnlineColoringChecker: public IChecker
{
public:
    OnlineColoringChecker():maxColor_(n + 1) {}
    OnlineColoringChecker(size_t maxColor):maxColor_(maxColor){}
    bool check(const ProcessState& state);
    std::string name() const
    {
        return "OnlineColoringChecker";
    }
    ~OnlineColoringChecker()
    {
        log();
    }
private:
    size_t maxColor_;
};

class OkChecker: public IChecker
{
public:
    bool check(const ProcessState& state)
    {
        return true;
    }
    std::string name() const
    {
        return "OkChecker";
    }
    ~OkChecker()
    {
        log();
    }
private:
};

class CombineChecker: public IChecker
{
public:
    bool check(const ProcessState& state)
    {
        for(size_t i = 0; i < checkers_.size(); ++i) {
            if (!checkers_[i].check(state)) {
                return false;
            }
        }
        return true;
    }
    std::string name() const
    {
        return "CombineChecker";
    }
    ~CombineChecker()
    {
    }
    void addChecker(std::auto_ptr<IChecker> checker)
    {
        checkers_.push_back(checker);
    }
    void addChecker(IChecker* checker)
    {
        checkers_.push_back(checker);
    }
private:
    boost::ptr_vector<IChecker> checkers_;
};

#endif//CHECKER_H
